package com.mgee.netty.server.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.google.protobuf.Any;
import com.google.protobuf.InvalidProtocolBufferException;
import com.mgee.netty.server.constant.MessagingConst;
import com.mgee.netty.server.dto.RemoteUserInfoDTO;
import com.mgee.netty.server.netty.IoSession;
import com.mgee.netty.server.netty.SessionManager;
import com.mgee.netty.server.netty.constant.CloudCubeConst;
import com.mgee.netty.server.netty.constant.CommonConstant;
import com.mgee.netty.server.pojo.ChatUserInfo;
import com.mgee.netty.server.pojo.NewChatUserInfo;
import com.mgee.netty.server.protobuf.ImProto;
import com.mgee.netty.server.util.JwtTokenUtil;
import com.mgee.netty.server.util.MessageBuilder;
import com.mgee.netty.server.util.RequestUtil;
import io.jsonwebtoken.Claims;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.TypeReference;

import javax.annotation.Resource;
import java.util.*;

@Service
@Slf4j
public class CloudCubeService {

    @Resource
    private RoomService roomService;

    @Resource
    private SessionManager sessionManager;

    public String ROOM_NO = "chimeta_card";


    public void broadcast(ImProto.ImMsg imMsg, IoSession currSession, ChannelHandlerContext ctx){
        try {
            ImProto.CloudCubeBroadcast cloudCubeBroadcast = imMsg.getMsg().unpack(ImProto.CloudCubeBroadcast.class);
            log.info("CloudCubeService broadcast cloudCubeBroadcast:{}", cloudCubeBroadcast.toString());

            int type = cloudCubeBroadcast.getType();
            switch (type){
                case CloudCubeConst.CLOUD_CUBE_TYPE_LOGIN:
                    handleLogin(imMsg, currSession);
                    break;
                case CloudCubeConst.CLOUD_CUBE_TYPE_JOIN:
                    roomService.newJoinRoom(imMsg, currSession);
                    break;
                case CloudCubeConst.CLOUD_CUBE_TYPE_LEAVE:
                    roomService.newExitRoom(imMsg, currSession);
                    break;
                default:
                    // 直接转发
                    handleTransmissionSync(imMsg, currSession);
                    break;
             }


        } catch (InvalidProtocolBufferException e) {
            log.error("CloudCubeService broadcast error:{}", e.getMessage());
            throw new RuntimeException(e);
        }
    }

    public void cardBroadcast(ImProto.ImMsg imMsg, IoSession currSession){
        try {
            ImProto.CardAbcBroadcastRequest cloudCubeBroadcastRequest = imMsg.getMsg().unpack(ImProto.CardAbcBroadcastRequest.class);
            log.info("CloudCubeService cardBroadcast cloudCubeBroadcastRequest:{}", cloudCubeBroadcastRequest.toString());
            // 直接转发
            handleCardTransmissionSync(imMsg, currSession);

        } catch (InvalidProtocolBufferException e) {
            log.error("CloudCubeService cardBroadcast error:{}", e.getMessage());
            throw new RuntimeException(e);
        }
    }

    private void handleTransmissionSync(ImProto.ImMsg imMsg, IoSession currSession) {
        if(currSession.getNewChatUserInfo() == null) {
            currSession.sendMessage(MessageBuilder.buildErrorResponse(imMsg, MessagingConst.RESPONSE_ERR_CODE_400, "用户未登录!"));
            return;
        }
        try {
            ImProto.CloudCubeBroadcast cloudCubeBroadcast = imMsg.getMsg().unpack(ImProto.CloudCubeBroadcast.class);
            if(Objects.isNull(cloudCubeBroadcast)) {
                currSession.sendMessage(MessageBuilder.buildErrorResponse(imMsg, MessagingConst.RESPONSE_ERR_CODE_400, "请求的参数错误,posPack不能为空!"));
                return;
            }

            String senderUid = currSession.getNewChatUserInfo().getUid();
            String groupId = SessionManager.userId2GroupIds.get(senderUid);
            if(StringUtils.isEmpty(groupId)) {
                currSession.sendMessage(MessageBuilder.buildErrorResponse(imMsg, MessagingConst.RESPONSE_ERR_CODE_400, "用户未在任何房间!用户id："+senderUid + "groupId:"+groupId));
                return;
            }
            //广播Rsp消息
            ImProto.CloudCubeBroadcastRep.Builder cloudCubeBroadcastResBuilder = ImProto.CloudCubeBroadcastRep.newBuilder();
            int type = cloudCubeBroadcast.getType();
            cloudCubeBroadcastResBuilder.setType(type);
//            cloudCubeBroadcastResBuilder.setRoomNo(cloudCubeBroadcast.getRoomNo());
            String roomNo = "chimeta";
            cloudCubeBroadcastResBuilder.setRoomNo(roomNo);
            cloudCubeBroadcastResBuilder.setUid(senderUid);
            cloudCubeBroadcastResBuilder.setPositionPack(cloudCubeBroadcast.getPositionPack());

            ImProto.CubePack cubePackReq = cloudCubeBroadcast.getCubePack();
            ImProto.CubePack.Builder cubePackBuilder = ImProto.CubePack.newBuilder();
            // 处理魔方的相关缓存
            if (type == CloudCubeConst.CLOUD_CUBE_TYPE_CUBE){
                cubePackBuilder.setX(cubePackReq.getX());
                cubePackBuilder.setY(cubePackReq.getY());
                cubePackBuilder.setZ(cubePackReq.getZ());
                cubePackBuilder.setSubId(cubePackReq.getSubId());
                cubePackBuilder.setUid(cubePackReq.getUid());
                cubePackBuilder.setUsername(cubePackReq.getUsername());

                int operate = cubePackReq.getOperate();
                cubePackBuilder.setOperate(operate);

//                log.info("CloudCubeService handleTransmissionSync before moveSubIdList:{}", sessionManager.moveSubIdList);

                List<Integer> moveSubIdList = SessionManager.moveSubIdList;
                log.info("CloudCubeService handleTransmissionSync now moveSubIdList:{}", JSON.toJSONString(moveSubIdList));
                for (Integer subId : moveSubIdList){
                    cubePackBuilder.addMoveSubIds(subId);
                }

                if (operate == 1){
                    sessionManager.addMoveSubIdList(cubePackReq.getSubId());
                }else if (operate == 2){
                    sessionManager.removeMoveSubId(cubePackReq.getSubId());
                }
                sessionManager.setTurnTableRotateWork(cloudCubeBroadcast.getTurnTableRotate());
                sessionManager.setCubeRotateWork(cloudCubeBroadcast.getCubeRotate());
            }

            cloudCubeBroadcastResBuilder.setCubePack(cubePackBuilder);
            cloudCubeBroadcastResBuilder.setResetPack(cloudCubeBroadcast.getResetPack());
            if (type == CloudCubeConst.CLOUD_CUBE_TYPE_RESET){
                ImProto.ResetPack resetPack = cloudCubeBroadcast.getResetPack();
                if (resetPack.getTurntable() == 1){
                    sessionManager.setTurnTableRotateWork(0);
                }
                if (resetPack.getCube() == 1) {
                    sessionManager.cleanMoveSubIdList();
                    sessionManager.setCubeRotateWork(0);
                }
                if (resetPack.getAll() == 1){
                    sessionManager.setTurnTableRotateWork(0);
                    sessionManager.cleanMoveSubIdList();
                    sessionManager.setCubeRotateWork(0);
                }
            }
            if (type == CloudCubeConst.CLOUD_CUBE_TYPE_TURN_TABLE_ROTATE){
                sessionManager.setTurnTableRotateWork(cloudCubeBroadcast.getTurnTableRotate());
            }else if (type == CloudCubeConst.CLOUD_CUBE_TYPE_CUBE_ROTATE){
                sessionManager.setCubeRotateWork(cloudCubeBroadcast.getCubeRotate());
            }
            cloudCubeBroadcastResBuilder.setTurnTableRotate(cloudCubeBroadcast.getTurnTableRotate());
            cloudCubeBroadcastResBuilder.setCubeRotate(cloudCubeBroadcast.getCubeRotate());

            ImProto.ImMsg.Builder imMsgBroadBuilder = ImProto.ImMsg.newBuilder();
            imMsgBroadBuilder.setMsg(Any.pack(cloudCubeBroadcastResBuilder.build()));
            imMsgBroadBuilder.setId(imMsg.getId());

            if (type == CloudCubeConst.CLOUD_CUBE_TYPE_POS){
                log.info("handleTransmissionSync type4 into");
                sessionManager.sendMessageToRoomUsers(imMsgBroadBuilder.build(), senderUid);
            }else{
                sessionManager.sendMessageToAllRoomUsers(imMsgBroadBuilder.build(), senderUid);
            }

        } catch (InvalidProtocolBufferException e) {
            throw new RuntimeException(e);
        }

    }

    private void handleCardTransmissionSync(ImProto.ImMsg imMsg, IoSession currSession) {
        if(currSession.getNewChatUserInfo() == null) {
            currSession.sendMessage(MessageBuilder.buildErrorResponse(imMsg, MessagingConst.RESPONSE_ERR_CODE_400, "cardBroadcast用户未登录!"));
            return;
        }
        try {
            ImProto.CardAbcBroadcastRequest cardAbcBroadcastRequest = imMsg.getMsg().unpack(ImProto.CardAbcBroadcastRequest.class);
            if(Objects.isNull(cardAbcBroadcastRequest)) {
                currSession.sendMessage(MessageBuilder.buildErrorResponse(imMsg, MessagingConst.RESPONSE_ERR_CODE_400, "card请求的参数错误,未能解析"));
                return;
            }

            String senderUid = currSession.getNewChatUserInfo().getUid();
            String groupId = SessionManager.userId2GroupIds.get(senderUid);
            if(StringUtils.isEmpty(groupId)) {
                currSession.sendMessage(MessageBuilder.buildErrorResponse(imMsg, MessagingConst.RESPONSE_ERR_CODE_400, "用户未在任何card房间!用户id："+senderUid + "groupId:"+groupId));
                return;
            }
            //广播Rsp消息
            ImProto.CardAbcBroadcastRep.Builder cardAbcBroadcastRepBuilder = ImProto.CardAbcBroadcastRep.newBuilder();
            cardAbcBroadcastRepBuilder.setXPosition(cardAbcBroadcastRequest.getXPosition());
            cardAbcBroadcastRepBuilder.setYPosition(cardAbcBroadcastRequest.getYPosition());
            cardAbcBroadcastRepBuilder.setZPosition(cardAbcBroadcastRequest.getZPosition());
            cardAbcBroadcastRepBuilder.setRx(cardAbcBroadcastRequest.getRx());
            cardAbcBroadcastRepBuilder.setRy(cardAbcBroadcastRequest.getRy());
            cardAbcBroadcastRepBuilder.setRz(cardAbcBroadcastRequest.getRz());
            cardAbcBroadcastRepBuilder.setSx(cardAbcBroadcastRequest.getSx());
            cardAbcBroadcastRepBuilder.setSy(cardAbcBroadcastRequest.getSy());
            cardAbcBroadcastRepBuilder.setSz(cardAbcBroadcastRequest.getSz());
            cardAbcBroadcastRepBuilder.setCardId(cardAbcBroadcastRequest.getCardId());

            ImProto.ImMsg.Builder imMsgBroadBuilder = ImProto.ImMsg.newBuilder();
            imMsgBroadBuilder.setMsg(Any.pack(cardAbcBroadcastRepBuilder.build()));
            imMsgBroadBuilder.setId(imMsg.getId());

            sessionManager.sendMessageToRoomUsers(imMsgBroadBuilder.build(), senderUid);

        } catch (InvalidProtocolBufferException e) {
            throw new RuntimeException(e);
        }

    }

    // 根据token请求获取用户信息
    private RemoteUserInfoDTO getRemoteUserInfoDTO(String token){
        Map<String, String> requestMap = new HashMap<>();
        requestMap.put("Authorization", token);
        String userRemoteResultStr = RequestUtil.sendGet("https://api-test.chimeta.com/v1/core/ums/getInfo", requestMap);
        log.info("CloudCubeService handleLogin token is:{}, userRemoteResult is:{}", token, userRemoteResultStr);
        RemoteUserInfoDTO remoteUserInfoDTO = null;
        if (StringUtils.isNotBlank(userRemoteResultStr)){
            JSONObject resultJsonObject = JSONObject.parseObject(userRemoteResultStr);
            if (resultJsonObject.getInteger("code") == 200){
                String dateStr = resultJsonObject.getString("data");
                remoteUserInfoDTO = JSON.parseObject(dateStr, new TypeReference<RemoteUserInfoDTO>() {
                });
            }
        }
        return remoteUserInfoDTO;
    }

    /**
     * 处理登录事件
     * 验证并处理从CloudCube广播收到的登录令牌（token）
     *
     * @param imMsg 云立方体广播对象，包含登录信息
     * @param currSession 当前会话对象，用于设置用户ID
     */
    private void handleLogin(ImProto.ImMsg imMsg, IoSession currSession) {

        ImProto.CloudCubeBroadcast cloudCubeBroadcast = null;
        try {
            cloudCubeBroadcast = imMsg.getMsg().unpack(ImProto.CloudCubeBroadcast.class);
        } catch (InvalidProtocolBufferException e) {
            throw new RuntimeException(e);
        }
        String errDesc = "";
        // 提取令牌字符串
        String token = cloudCubeBroadcast.getToken();
        // 如果令牌不为空，则尝试解析
        if (StringUtils.isNotBlank(token)) {
            // 从令牌中获取用户声明
            RemoteUserInfoDTO remoteUserInfoDTO = getRemoteUserInfoDTO(token);
            boolean isLoginSuccess = Objects.nonNull(remoteUserInfoDTO);
            errDesc = isLoginSuccess ? "登录成功！" : "登录失败！";
            NewChatUserInfo sendNewChatUserInfo = null;
            if (Objects.nonNull(remoteUserInfoDTO)){
                // 提取并记录用户ID
                NewChatUserInfo newChatUserInfo = generateNewChatUserInfo(remoteUserInfoDTO, token);

                IoSession existSession = SessionManager.userId2Sessions.get(newChatUserInfo.getUsername());
                if (existSession != null && existSession.getNewChatUserInfo()!= null){
                    sendNewChatUserInfo = existSession.getNewChatUserInfo();
                }else {
                    sendNewChatUserInfo = new NewChatUserInfo();
                    sendNewChatUserInfo.setUid(newChatUserInfo.getUid());
                    sendNewChatUserInfo.setUsername(newChatUserInfo.getUsername());
                    sendNewChatUserInfo.setPhone(remoteUserInfoDTO.getTelephone());
                    sendNewChatUserInfo.setChimetaToken(token);
                }
                // 存个用户session，后期要用
                sessionManager.newRegisterSession(sendNewChatUserInfo, currSession);
                currSession.setNewChatUserInfo(newChatUserInfo);
            }
            ImProto.ImMsg responseMsg = buildLoginResponse(imMsg,
                    isLoginSuccess,
                    errDesc,
                    Objects.isNull(sendNewChatUserInfo.getUid()) ? "" : sendNewChatUserInfo.getUid(),
                    Objects.isNull(sendNewChatUserInfo.getUsername()) ? "" : sendNewChatUserInfo.getUsername()
                    );

            //发送反馈消息
            currSession.sendMessageTwo(responseMsg);
        } else {
            // 令牌为空，记录错误日志
            log.error("CloudCubeService broadcast error token is empty");
            currSession.sendMessage(MessageBuilder.buildErrorResponse(imMsg, MessagingConst.RESPONSE_ERR_CODE_400, "token is empty!"));
        }

    }

    /**
     * 处理卡牌登录事件
     * 验证并处理从CloudCube广播收到的登录令牌（token）
     *
     * @param imMsg 云立方体广播对象，包含登录信息
     * @param currSession 当前会话对象，用于设置用户ID
     */
    public void handleCardAbcLogin(ImProto.ImMsg imMsg, IoSession currSession) {

        ImProto.CardAbcLoginRequest cardAbcLoginRequest = null;
        try {
            cardAbcLoginRequest = imMsg.getMsg().unpack(ImProto.CardAbcLoginRequest.class);
        } catch (InvalidProtocolBufferException e) {
            throw new RuntimeException(e);
        }
        String errDesc = "";
        // 提取令牌字符串
        String token = cardAbcLoginRequest.getToken();
        // 如果令牌不为空，则尝试解析
        if (StringUtils.isNotBlank(token)) {
            // 从令牌中获取用户声明
            RemoteUserInfoDTO remoteUserInfoDTO = getRemoteUserInfoDTO(token);
            boolean isLoginSuccess = Objects.nonNull(remoteUserInfoDTO);
            errDesc = isLoginSuccess ? "登录成功！" : "登录失败！";
            NewChatUserInfo sendNewChatUserInfo = null;
            if (Objects.nonNull(remoteUserInfoDTO)){
                // 提取并记录用户ID
                NewChatUserInfo newChatUserInfo = generateNewChatUserInfo(remoteUserInfoDTO, token);

                IoSession existSession = SessionManager.userId2Sessions.get(newChatUserInfo.getUsername());
                if (existSession != null && existSession.getNewChatUserInfo()!= null){
                    sendNewChatUserInfo = existSession.getNewChatUserInfo();
                }else {
                    sendNewChatUserInfo = new NewChatUserInfo();
                    sendNewChatUserInfo.setUid(newChatUserInfo.getUid());
                    sendNewChatUserInfo.setUsername(newChatUserInfo.getUsername());
                    sendNewChatUserInfo.setPhone(remoteUserInfoDTO.getTelephone());
                    sendNewChatUserInfo.setChimetaToken(token);
                }
                // 存个用户session，后期要用
                sessionManager.newRegisterSession(sendNewChatUserInfo, currSession);
                currSession.setNewChatUserInfo(newChatUserInfo);
            }
            ImProto.ImMsg responseMsg = buildLoginResponse(imMsg,
                    isLoginSuccess,
                    errDesc,
                    Objects.isNull(sendNewChatUserInfo) ? "" : sendNewChatUserInfo.getUid(),
                    Objects.isNull(sendNewChatUserInfo) ? "" : sendNewChatUserInfo.getUsername()
            );

            //当前用户发送反馈消息
            currSession.sendMessageTwo(responseMsg);
        } else {
            // 令牌为空，记录错误日志
            log.error("CloudCubeService handleCardAbcLogin error token is empty");
            currSession.sendMessage(MessageBuilder.buildErrorResponse(imMsg, MessagingConst.RESPONSE_ERR_CODE_400, "token is empty!"));
        }

    }

    /**
     * 根据换到的信息封装成NewChatUserInfo
     * @param remoteUserInfoDTO
     * @return
     */
    private NewChatUserInfo generateNewChatUserInfo(RemoteUserInfoDTO remoteUserInfoDTO, String token){
        String lastSenderUsername = StringUtils.isNotBlank(remoteUserInfoDTO.getUsername()) ? remoteUserInfoDTO.getUsername() : remoteUserInfoDTO.getTelephone();
        String uid = remoteUserInfoDTO.getUid();
        NewChatUserInfo newChatUserInfo = new NewChatUserInfo();
        newChatUserInfo.setUid(uid);
        newChatUserInfo.setUsername(lastSenderUsername);
        newChatUserInfo.setPhone(remoteUserInfoDTO.getTelephone());
        newChatUserInfo.setChimetaToken(token);
        log.info("CloudCubeService handleLogin chatUserInfo is:{}", JSON.toJSONString(newChatUserInfo));
        return newChatUserInfo;
    }

    /**
     * 构建登录返回消息体
     * @param imMsg
     * @param isSuccess
     * @param errDesc
     * @return
     */
    private ImProto.ImMsg buildResponse(ImProto.ImMsg imMsg, boolean isSuccess, String errDesc) {
        try {
            ImProto.UserloginRsp.Builder loginResponseBuilder = ImProto.UserloginRsp.newBuilder();
            ImProto.ImMsg.Builder imMsgBuilder = ImProto.ImMsg.newBuilder();

            loginResponseBuilder.setResult(isSuccess);
            loginResponseBuilder.setDescription(errDesc);
            ImProto.UserloginRsp loginResponse = loginResponseBuilder.build();

            imMsgBuilder.setMsg(Any.pack(loginResponse));
            imMsgBuilder.setId(imMsg.getId());

            return imMsgBuilder.build();
        }catch(Exception e) {
            log.error("构建登录返回消息体时发生异常：", e);
            return null;
        }
    }

    /**
     * 构建登录返回消息体
     * @param imMsg
     * @param isSuccess
     * @param errDesc
     * @return
     */
    private ImProto.ImMsg buildLoginResponse(ImProto.ImMsg imMsg, boolean isSuccess, String errDesc, String uid, String username) {
        try {
            ImProto.UserloginRsp.Builder loginResponseBuilder = ImProto.UserloginRsp.newBuilder();
            ImProto.ImMsg.Builder imMsgBuilder = ImProto.ImMsg.newBuilder();

            loginResponseBuilder.setResult(isSuccess);
            loginResponseBuilder.setDescription(errDesc);
            loginResponseBuilder.setUid(uid);
            loginResponseBuilder.setUsername(username);
            // 获取魔方已移动的方块和旋转角度
            List<Integer> moveSubIdList = SessionManager.moveSubIdList;
            for (Integer subId : moveSubIdList){
//                loginResponseBuilder.addMoveSubIds(subId);// 去掉
            }
            // 获取盘子旋转角度返回
            Integer turnTableRotate = sessionManager.getTurnTableRotateWork();
//            loginResponseBuilder.setTurnTableRotate(turnTableRotate);// 去掉
            // 获取魔方旋转角度返回
            Integer cubeRotate = sessionManager.getCubeRotateWork();
//            loginResponseBuilder.setCubeRotate(cubeRotate);// 去掉
            log.info("buildResponseNew now moveSubIdList:{}, rotate:{}", JSON.toJSONString(moveSubIdList), turnTableRotate);
            log.info("buildResponseNew loginResponseBuilder:{}", String.valueOf(loginResponseBuilder));
            ImProto.UserloginRsp loginResponse = loginResponseBuilder.build();
            imMsgBuilder.setMsg(Any.pack(loginResponse));
            imMsgBuilder.setId(imMsg.getId());

            return imMsgBuilder.build();
        }catch(Exception e) {
            log.error("构建登录返回消息体时发生异常：", e);
            return null;
        }
    }

}
